package com.cpm.repository.jpa;

import com.cpm.repository.Filter;
import com.uaihebert.cto.UaiCTOImp;
import com.uaihebert.uaicriteria.UaiCriteriaFactory;
import java.util.List;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.metamodel.Attribute;

public class DefaultFilterJpa implements Filter {

    @PersistenceContext
    private EntityManager entityManager;
    private final UaiCTOImp uaiCriteria = new UaiCTOImp();
    
    private DefaultFilterJpa() {
    }

    @Override
    public <T> List<T> getResultList(Class<T> entity) {
        return UaiCriteriaFactory.createQueryCriteria(entityManager, entity, uaiCriteria).getResultList();
    }

    @Override
    public <T> T getSingleResult(Class<T> entity) {
        return (T) UaiCriteriaFactory.createQueryCriteria(entityManager, entity, uaiCriteria).getSingleResult();
    }

    @Override
    public Long count(Class entity) {
        return UaiCriteriaFactory.createQueryCriteria(entityManager, entity, uaiCriteria).countRegularCriteria();
    }

    @Override
    public List getMultiSelectResult(Class entity) {
        return UaiCriteriaFactory.createMultiSelectCriteria(entityManager, entity, uaiCriteria).getMultiSelectResult();
    }

    @Override
    public DefaultFilterJpa andEquals(final Attribute attributeName, final Object value) {
        uaiCriteria.andEquals(attributeName.getName(), value);
        return this;
    }

    public DefaultFilterJpa andEqualsIgnoreCase(final Attribute attributeName, final Object value) {
        uaiCriteria.andEquals(true, attributeName.getName(), value.toString());
        return this;
    }

    public DefaultFilterJpa orEquals(final Attribute attributeName, final Object... valueArray) {
        uaiCriteria.orEquals(attributeName.getName(), valueArray);
        return this;
    }

    public DefaultFilterJpa orEqualsIgnoreCase(final Attribute attributeName, final Object... valueArray) {
        uaiCriteria.orEquals(true, attributeName.getName(), arrayObjectToArrayString(valueArray));
        return this;
    }

    public DefaultFilterJpa andStringLike(final Attribute attributeName, final String value) {
        uaiCriteria.andStringLike(attributeName.getName(), value);
        return this;
    }

    public DefaultFilterJpa andStringLikeIgnoreCase(final Attribute attributeName, final String value) {
        uaiCriteria.andStringLike(true, attributeName.getName(), value);
        return this;
    }

    public DefaultFilterJpa andStringNotLike(final Attribute attributeName, final String value) {
        uaiCriteria.andStringNotLike(attributeName.getName(), value);
        return this;
    }

    public DefaultFilterJpa andStringNotLikeIgnoreCase(final Attribute attributeName, final String value) {
        uaiCriteria.andStringNotLike(true, attributeName.getName(), value);
        return this;
    }

    public DefaultFilterJpa orStringLike(final Attribute attributeName, String... stringArray) {
        uaiCriteria.orStringNotLike(attributeName.getName(), stringArray);
        return this;
    }

    public DefaultFilterJpa orStringLikeIgnoreCase(final Attribute attributeName, String... stringArray) {
        uaiCriteria.orStringNotLike(true, attributeName.getName(), stringArray);
        return this;
    }

    public DefaultFilterJpa orStringNotLike(final Attribute attributeName, String... stringArray) {
        uaiCriteria.orStringNotLike(attributeName.getName(), stringArray);
        return this;
    }

    public DefaultFilterJpa orStringNotLikeIgnoreCase(final Attribute attributeName, String... stringArray) {
        uaiCriteria.orStringNotLike(true, attributeName.getName(), stringArray);
        return this;
    }

    public DefaultFilterJpa andNotEquals(final Attribute attributeName, final Object value) {
        uaiCriteria.andNotEquals(attributeName.getName(), value);
        return this;
    }

    public DefaultFilterJpa andNotEqualsIgnoreCase(final Attribute attributeName, final Object value) {
        uaiCriteria.andNotEquals(true, attributeName.getName(), value.toString());
        return this;
    }

    public DefaultFilterJpa orNotEquals(final Attribute attributeName, final Object... valueArray) {
        uaiCriteria.orNotEquals(attributeName.getName(), valueArray);
        return this;
    }

    public DefaultFilterJpa orNotEqualsIgnoreCase(final Attribute attributeName, final Object... valueArray) {
        uaiCriteria.orNotEquals(true, attributeName.getName(), arrayObjectToArrayString(valueArray));
        return this;
    }

    public DefaultFilterJpa setDistinctTrue() {
        uaiCriteria.setDistinctTrue();
        return this;
    }

    public DefaultFilterJpa andBetween(final Attribute attributeName, final Object valueA, final Object valueB) {
        uaiCriteria.andBetween(attributeName.getName(), valueA, valueB);
        return this;
    }

    public DefaultFilterJpa andBetweenIgnoreCase(final Attribute attributeName, final Object valueA, final Object valueB) {
        uaiCriteria.andBetween(true, attributeName.getName(), valueA.toString(), valueB.toString());
        return this;
    }

    public DefaultFilterJpa andIsNull(final Attribute attributeName) {
        uaiCriteria.andIsNull(attributeName.getName());
        return this;
    }

    public DefaultFilterJpa orIsNull(final Attribute attributeName) {
        uaiCriteria.orIsNull(attributeName.getName());
        return this;
    }

    public DefaultFilterJpa andIsNotNull(final Attribute attributeName) {
        uaiCriteria.andIsNotNull(attributeName.getName());
        return this;
    }

    public DefaultFilterJpa orIsNotNull(final Attribute attributeName) {
        uaiCriteria.orIsNotNull(attributeName.getName());
        return this;
    }

    public <E> DefaultFilterJpa andAttributeIn(final Attribute attributeName, final List<E> attributeList) {
        uaiCriteria.andAttributeIn(attributeName.getName(), attributeList);
        return this;
    }

//    @Override
//    public <E> DefaultFilterJpa andAttributeIn(Attribute attributeName, Filter<E> subQuery) {
//        uaiCriteria.andAttributeIn(attributeName.getName(), ((DefaultFilterJpa) subQuery));
//        return this;
//    }

    public <E> DefaultFilterJpa andAttributeNotIn(final Attribute attributeName, final List<E> attributeList) {
        uaiCriteria.andAttributeNotIn(attributeName.getName(), attributeList);
        return this;
    }

//    @Override
//    public <E> DefaultFilterJpa andAttributeNotIn(Attribute attributeName, Filter<E> subQuery) {
//        uaiCriteria.andAttributeNotIn(attributeName.getName(), ((DefaultFilterJpa) subQuery).getUaiCriteriaCTO());
//        return this;
//    }

    public DefaultFilterJpa andStringIn(final Attribute attributeName, final List<String> valueList) {
        uaiCriteria.andStringIn(attributeName.getName(), valueList);
        return this;
    }

    public DefaultFilterJpa andStringInIgnoreCase(final Attribute attributeName, final List<String> valueList) {
        uaiCriteria.andStringIn(true, attributeName.getName(), valueList);
        return this;
    }

    public DefaultFilterJpa andStringNotIn(final Attribute attributeName, final List<String> valueList) {
        uaiCriteria.andStringNotIn(attributeName.getName(), valueList);
        return this;
    }

    public DefaultFilterJpa andStringNotInIgnoreCase(final Attribute attributeName, final List<String> valueList) {
        uaiCriteria.andStringNotIn(true, attributeName.getName(), valueList);
        return this;
    }

    public DefaultFilterJpa orderByAsc(final Attribute attributeName) {
        uaiCriteria.orderByAsc(attributeName.getName());
        return this;
    }

    public DefaultFilterJpa orderByDesc(final Attribute attributeName) {
        uaiCriteria.orderByDesc(attributeName.getName());
        return this;
    }
    
    public Filter setFirstResult(final Integer firstResult){
        uaiCriteria.setFirstResult(firstResult);
        return this;
    }

    public DefaultFilterJpa setMaxResults(final Integer maxResults) {
        uaiCriteria.setMaxResults(maxResults);
        return this;
    }
    
    public Filter countAttribute(final Attribute... attributeNameArray){
        uaiCriteria.countAttribute(arrayAttributeToArrayString(attributeNameArray));
        return this;
    }

    @Override
    public DefaultFilterJpa sum(final Attribute... attributeNameArray) {
        uaiCriteria.sum(arrayAttributeToArrayString(attributeNameArray));
        return this;
    }

    @Override
    public DefaultFilterJpa multiply(final Attribute firstAttribute, final Attribute secondAttribute) {
        uaiCriteria.multiply(firstAttribute.getName(), secondAttribute.getName());
        return this;
    }

    public DefaultFilterJpa divide(final Attribute firstAttribute, final Attribute secondAttribute) {
        uaiCriteria.divide(firstAttribute.getName(), secondAttribute.getName());
        return this;
    }

    public DefaultFilterJpa average(final Attribute... attributeNameArray) {
        uaiCriteria.average(arrayAttributeToArrayString(attributeNameArray));
        return this;
    }

    public DefaultFilterJpa square(final Attribute... attributeNameArray) {
        uaiCriteria.square(arrayAttributeToArrayString(attributeNameArray));
        return this;
    }

    public DefaultFilterJpa groupBy(final Attribute... attributeNameArray) {
        uaiCriteria.groupBy(arrayAttributeToArrayString(attributeNameArray));
        return this;
    }

    private String[] arrayAttributeToArrayString(Attribute... valueArray) {
        return Stream.of(valueArray).map(Attribute::getName).toArray(String[]::new);
    }
    
    private String[] arrayObjectToArrayString(Object... valueArray) {
        return Stream.of(valueArray).map(String::valueOf).toArray(String[]::new);
    }
}
